<!-- @format -->

<template>
  <view
    class="comp-switch"
    :class="[
      { 'comp-switch--checked': isChecked },
      { 'comp-switch--disabled': disabled },
      { 'comp-switch--loading': loading },
      `comp-switch--${size}`,
    ]"
    :style="{
      backgroundColor: isChecked ? activeColor : inactiveColor,
      '--active-color': activeColor,
      '--inactive-color': inactiveColor,
    }"
    @click="handleClick"
  >
    <!-- 开关轨道 -->
    <view class="comp-switch__node">
      <!-- 加载图标 -->
      <view v-if="loading" class="comp-switch__loading"></view>
    </view>

    <!-- 标签内容 -->
    <view v-if="label || $slots.default" class="comp-switch__label">
      <slot>{{ label }}</slot>
    </view>
  </view>
</template>

<script setup lang="ts">
  import { computed, ref } from 'vue';
  import { SwitchProps, SwitchEvents, SwitchMethods } from './types';

  // 定义默认属性
  const props = withDefaults(defineProps<SwitchProps>(), {
    modelValue: false,
    disabled: false,
    loading: false,
    label: '',
    activeColor: '#1989fa',
    inactiveColor: '#dcdee0',
    size: 'medium',
    activeValue: true,
    inactiveValue: false,
  });

  // 定义事件
  const emit: any = defineEmits<SwitchEvents>();

  // 计算是否选中
  const isChecked = computed(() => {
    return props.modelValue === props.activeValue;
  });

  // 处理点击事件
  const handleClick = (event: Event) => {
    if (props.disabled || props.loading) {
      return;
    }

    const newValue = !isChecked.value;
    const emitValue = newValue ? props.activeValue : props.inactiveValue;

    emit('update:modelValue', newValue);
    emit('change', emitValue);
    emit('click', event);
  };

  // 暴露方法
  defineExpose<SwitchMethods>({
    /** 获取当前选中状态 */
    isChecked: () => isChecked.value,
    /** 设置选中状态 */
    setChecked: (checked: boolean) => {
      if (!props.disabled && !props.loading) {
        emit('update:modelValue', checked);
        emit('change', checked ? props.activeValue : props.inactiveValue);
      }
    },
    /** 切换选中状态 */
    toggle: () => {
      if (!props.disabled && !props.loading) {
        handleClick(new Event('click'));
      }
    },
  });
</script>

<style lang="scss">
  .comp-switch {
    position: relative;
    display: inline-flex;
    align-items: center;
    box-sizing: content-box;
    width: 50px;
    height: 30px;
    border-radius: 15px;
    background-color: #dcdee0;
    cursor: pointer;
    transition: all 0.3s;
    user-select: none;

    &__node {
      position: absolute;
      top: 2px;
      left: 2px;
      width: 26px;
      height: 26px;
      border-radius: 50%;
      background-color: #fff;
      box-shadow:
        0 3px 1px 0 rgba(0, 0, 0, 0.05),
        0 2px 2px 0 rgba(0, 0, 0, 0.1),
        0 3px 3px 0 rgba(0, 0, 0, 0.05);
      transition: all 0.3s cubic-bezier(0.18, 0.89, 0.32, 1.28);
      display: flex;
      align-items: center;
      justify-content: center;
    }

    &__loading {
      width: 14px;
      height: 14px;
      border: 2px solid transparent;
      border-top-color: var(--active-color, #1989fa);
      border-radius: 50%;
      animation: comp-switch-loading 0.8s infinite linear;
    }

    &__label {
      margin-left: 60px;
      color: #323233;
      font-size: 14px;
    }

    // 选中状态
    &--checked {
      .comp-switch__node {
        left: calc(100% - 28px);
      }
    }

    // 禁用状态
    &--disabled {
      cursor: not-allowed;
      opacity: 0.6;
    }

    // 加载状态
    &--loading {
      cursor: default;
    }

    // 尺寸变体
    &--small {
      width: 40px;
      height: 24px;
      border-radius: 12px;

      .comp-switch__node {
        width: 20px;
        height: 20px;
      }

      .comp-switch__loading {
        width: 10px;
        height: 10px;
      }

      .comp-switch__label {
        margin-left: 50px;
        font-size: 12px;
      }

      &.comp-switch--checked .comp-switch__node {
        left: calc(100% - 22px);
      }
    }

    &--large {
      width: 60px;
      height: 36px;
      border-radius: 18px;

      .comp-switch__node {
        width: 32px;
        height: 32px;
      }

      .comp-switch__loading {
        width: 18px;
        height: 18px;
      }

      .comp-switch__label {
        margin-left: 70px;
        font-size: 16px;
      }

      &.comp-switch--checked .comp-switch__node {
        left: calc(100% - 34px);
      }
    }
  }

  @keyframes comp-switch-loading {
    0% {
      transform: rotate(0deg);
    }
    100% {
      transform: rotate(360deg);
    }
  }
</style>
